package com.tuya.smart.android.demo.base.widget.contact;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.widget.Adapter;
import android.widget.ListView;
import android.widget.SectionIndexer;

// taken from https://github.com/woozzu/indexableListView IndexScroller
// rewrite some sections to make it more customizable
public class IndexScroller {

    /**
     * Add additional properties for customization
     */
    // Hung - store the last touch down eventX and eventY so that we can detect where user click on list view
    // indexscroller will override touch event of listview, so onclicklistener will not work
    private float lastTouchDownEventX = -1;
    private float lastTouchDownEventY = -1;

    // whether to autohide the scroller
    // false will always show the index bar
    // true will hide the scrollbar at first, but slowly show it later
    private boolean autoHide = false;

    // minor optimizations
    private Paint indexbarContainerPaint = new Paint(); // paint for indexbar container
    private Paint indexPaint = new Paint();

    private boolean showIndexContainer = false; // whether to show the outer index container
    private int indexbarContainerBgColor = Color.BLACK;
    private int indexPaintColor = Color.BLACK; // color for section title


    /// end additional properties

    private float mIndexbarWidth;
    private float mIndexbarMargin;
    private float mPreviewPadding;
    private float mDensity;
    private float mScaledDensity;
    private float mAlphaRate;
    private int mState = STATE_HIDDEN;
    private int mListViewWidth;
    private int mListViewHeight;
    private int mCurrentSection = -1;
    private boolean mIsIndexing = false;
    private ListView mListView = null;
    private SectionIndexer mIndexer = null;
    private String[] mSections = null;
    private RectF mIndexbarRect;

    private static final int STATE_HIDDEN = 0;
    private static final int STATE_SHOWING = 1;
    private static final int STATE_SHOWN = 2;
    private static final int STATE_HIDING = 3;


    public IndexScroller(Context context, ListView lv) {
        mDensity = context.getResources().getDisplayMetrics().density;
        mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
        mListView = lv;

        setAdapter(mListView.getAdapter());

        mIndexbarWidth = 20 * mDensity;
        mIndexbarMargin = 10 * mDensity;
        mPreviewPadding = mDensity;


        // customization of paint colors
        // outer container
        indexbarContainerPaint.setAntiAlias(true);

        // letter in section
        indexPaint.setAntiAlias(true);
        indexPaint.setTextSize(16 * mScaledDensity);
    }

    public IndexScroller(Context context, ListView lv, SectionIndexer indexer) {
        this(context, lv);

        mIndexer = indexer;

    }


    // draw the outer rounded container
    public void drawIndexBarContainer(Canvas canvas) {
        indexbarContainerPaint.setColor(indexbarContainerBgColor);
        indexbarContainerPaint.setAlpha(25); // opacity
        canvas.drawRoundRect(mIndexbarRect, 5 * mDensity, 5 * mDensity, indexbarContainerPaint);
    }

    public void drawSections(Canvas canvas) {
        indexPaint.setColor(indexPaintColor);

        float sectionHeight = (mIndexbarRect.height() - 2 * mIndexbarMargin) / mSections.length;
        float paddingTop = (sectionHeight - (indexPaint.descent() - indexPaint.ascent())) / 2;

        // draw the section letters
        for (int i = 0; i < mSections.length; i++) {
            float paddingLeft = (mIndexbarWidth - indexPaint.measureText(mSections[i])) / 2;
            canvas.drawText(mSections[i], mIndexbarRect.left + paddingLeft
                    , mIndexbarRect.top + mIndexbarMargin + sectionHeight * i + paddingTop - indexPaint.ascent(), indexPaint);
        }
    }

    public void drawCurrentSection(Canvas canvas) {
        if (mCurrentSection >= 0) {

            //Log.i("IndexScroller", "current section: " + mCurrentSection);

            // Preview is shown when mCurrentSection is set
            // mCurrentSection is the letter that is being pressed
            // this will draw the big preview text on top of the listview
            Paint previewPaint = new Paint();
            previewPaint.setColor(Color.BLACK);
            previewPaint.setAlpha(96);
            previewPaint.setAntiAlias(true);
            previewPaint.setShadowLayer(3, 0, 0, Color.argb(64, 0, 0, 0));

            Paint previewTextPaint = new Paint();
            previewTextPaint.setColor(Color.WHITE);
            previewTextPaint.setAntiAlias(true);
            previewTextPaint.setTextSize(50 * mScaledDensity);

            float previewTextWidth = previewTextPaint.measureText(mSections[mCurrentSection]);
            float previewSize = 2 * mPreviewPadding + previewTextPaint.descent() - previewTextPaint.ascent();
            RectF previewRect = new RectF((mListViewWidth - previewSize) / 2
                    , (mListViewHeight - previewSize) / 2
                    , (mListViewWidth - previewSize) / 2 + previewSize
                    , (mListViewHeight - previewSize) / 2 + previewSize);

            canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint);
            canvas.drawText(mSections[mCurrentSection], previewRect.left + (previewSize - previewTextWidth) / 2 - 1
                    , previewRect.top + mPreviewPadding - previewTextPaint.ascent() + 1, previewTextPaint);
        }
    }


    public void draw(Canvas canvas) {
        if (mState == STATE_HIDDEN)
            return;

        if (showIndexContainer)
            drawIndexBarContainer(canvas);

        if (mSections != null && mSections.length > 0) {

            drawCurrentSection(canvas);
            drawSections(canvas);
        }
    }

    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastTouchDownEventX = ev.getX(); // Hung capture the event for later use in listview item click
                lastTouchDownEventY = ev.getY();

                // If down event occurs inside index bar region, start indexing
                if (mState != STATE_HIDDEN && contains(ev.getX(), ev.getY())) {
                    setState(STATE_SHOWN);

                    // It demonstrates that the motion event started from index bar
                    mIsIndexing = true;
                    // Determine which section the point is in, and move the list to that section
                    mCurrentSection = getSectionByPoint(ev.getY());
                    mListView.setSelection(mIndexer.getPositionForSection(mCurrentSection));
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mIsIndexing) {
                    // If this event moves inside index bar
                    if (contains(ev.getX(), ev.getY())) {
                        // Determine which section the point is in, and move the list to that section
                        mCurrentSection = getSectionByPoint(ev.getY());
                        mListView.setSelection(mIndexer.getPositionForSection(mCurrentSection));
                    }
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mIsIndexing) {
                    mIsIndexing = false;
                    mCurrentSection = -1;
                }
                // only hide if state is auto hiding
                if (autoHide) {
                    if (mState == STATE_SHOWN)
                        setState(STATE_HIDING);
                }
                break;
        }
        return false;
    }

    public void onSizeChanged(int w, int h, int oldw, int oldh) {
        mListViewWidth = w;
        mListViewHeight = h;
        mIndexbarRect = new RectF(w - mIndexbarMargin - mIndexbarWidth
                , mIndexbarMargin
                , w - mIndexbarMargin
                , h - mIndexbarMargin);
    }

    public void show() {
        if (mState == STATE_HIDDEN)
            setState(STATE_SHOWING);
        else if (mState == STATE_HIDING)
            setState(STATE_HIDING);
    }

    public void hide() {
        if (mState == STATE_SHOWN)
            setState(STATE_HIDING);
    }

    public void setAdapter(Adapter adapter) {
        if (adapter instanceof SectionIndexer) {
            mIndexer = (SectionIndexer) adapter;
            mSections = (String[]) mIndexer.getSections();
        } else if (adapter instanceof ContactListAdapter) {
            ContactListAdapter c = (ContactListAdapter) adapter;
            mIndexer = c.getIndexer();
            mSections = (String[]) mIndexer.getSections();
        }
    }

    private void setState(int state) {
        if (state < STATE_HIDDEN || state > STATE_HIDING)
            return;

        mState = state;
        switch (mState) {
            case STATE_HIDDEN:
                // Cancel any fade effect
                mHandler.removeMessages(0);
                break;
            case STATE_SHOWING:
                // Start to fade in
                mAlphaRate = 0;
                fade(0);
                break;
            case STATE_SHOWN:
                // Cancel any fade effect
                mHandler.removeMessages(0);
                break;
            case STATE_HIDING:
                // Start to fade out after three seconds
                mAlphaRate = 1;
                fade(3000);
                break;
        }
    }

    private boolean contains(float x, float y) {
        // Determine if the point is in index bar region, which includes the right margin of the bar
        if (mIsIndexing) return true;
        return (x >= mIndexbarRect.left && y >= mIndexbarRect.top && y <= mIndexbarRect.top + mIndexbarRect.height());
    }

    private int getSectionByPoint(float y) {
        if (mSections == null || mSections.length == 0)
            return 0;
        if (y < mIndexbarRect.top + mIndexbarMargin)
            return 0;
        if (y >= mIndexbarRect.top + mIndexbarRect.height() - mIndexbarMargin)
            return mSections.length - 1;
        return (int) ((y - mIndexbarRect.top - mIndexbarMargin) / ((mIndexbarRect.height() - 2 * mIndexbarMargin) / mSections.length));
    }

    private void fade(long delay) {
        mHandler.removeMessages(0);
        mHandler.sendEmptyMessageAtTime(0, SystemClock.uptimeMillis() + delay);
    }

    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            switch (mState) {
                case STATE_SHOWING:
                    // Fade in effect
                    mAlphaRate += (1 - mAlphaRate) * 0.2;
                    if (mAlphaRate > 0.9) {
                        mAlphaRate = 1;
                        setState(STATE_SHOWN);
                    }

                    mListView.invalidate();
                    fade(10);
                    break;
                case STATE_SHOWN:
                    // If no action, hide automatically
                    // Hung - comment out this to disable hiding
                    if (autoHide) {
                        setState(STATE_HIDING);
                    }
                    break;
                case STATE_HIDING:
                    // Fade out effect
                    mAlphaRate -= mAlphaRate * 0.2;
                    if (mAlphaRate < 0.1) {
                        mAlphaRate = 0;
                        setState(STATE_HIDDEN);
                    }

                    mListView.invalidate();
                    fade(10);
                    break;
            }
        }

    };

    public float getLastTouchDownEventX() {
        return lastTouchDownEventX;
    }

    public void setLastTouchDownEventX(float lastTouchDownEventX) {
        this.lastTouchDownEventX = lastTouchDownEventX;
    }

    public float getLastTouchDownEventY() {
        return lastTouchDownEventY;
    }

    public void setLastTouchDownEventY(float lastTouchDownEventY) {
        this.lastTouchDownEventY = lastTouchDownEventY;
    }

    public boolean isAutoHide() {
        return autoHide;
    }

    public void setAutoHide(boolean autoHide) {
        this.autoHide = autoHide;
    }

    public boolean isShowIndexContainer() {
        return showIndexContainer;
    }

    public void setShowIndexContainer(boolean showIndexContainer) {
        this.showIndexContainer = showIndexContainer;
    }

    public int getIndexbarContainerBgColor() {
        return indexbarContainerBgColor;
    }

    public void setIndexbarContainerBgColor(int indexbarContainerBgColor) {
        this.indexbarContainerBgColor = indexbarContainerBgColor;
    }

    public int getIndexPaintColor() {
        return indexPaintColor;
    }

    public void setIndexPaintColor(int indexPaintColor) {
        this.indexPaintColor = indexPaintColor;
    }


}
